Slide 1: Introduction to Solidity


Slide 2: Basic Programming Structure

Code Example: Basic Smart Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract HelloWorld {
    string public greeting = "Hello, World!";

    function getGreeting() public view returns (string memory) {
        return greeting;
    }
}

Slide 3: Control Flow

Code Example: Control Flow

pragma solidity ^0.8.0;

contract ControlFlow {
    function checkNumber(uint num) public pure returns (string memory) {
        if (num > 10) {
            return "Greater than 10";
        } else if (num == 10) {
            return "Equal to 10";
        } else {
            return "Less than 10";
        }
    }
}

Slide 4: Data Types

Code Example: Data Types

pragma solidity ^0.8.0;

contract DataTypes {
    uint public number = 42;
    bool public isTrue = true;
    address public owner = msg.sender;
    bytes32 public data = "Hello";

    function updateNumber(uint _number) public {
        number = _number;
    }
}

Slide 5: Variables

Code Example: Variables

pragma solidity ^0.8.0;

contract Variables {
    uint public stateVariable = 10; // State variable

    function getLocalVariable() public pure returns (uint) {
        uint localVariable = 20; // Local variable
        return localVariable;
    }

    function getGlobalVariable() public view returns (address) {
        return msg.sender; // Global variable
    }
}

Slide 6: Operators

Code Example: Operators

pragma solidity ^0.8.0;

contract Operators {
    function calculate(uint a, uint b) public pure returns (uint) {
        uint sum = a + b;
        uint product = a * b;
        return sum + product;
    }
}

Slide 7: State Variables and Storage

Code Example: State Variables and Storage

pragma solidity ^0.8.0;

contract StorageExample {
    uint public storedData;

    function set(uint x) public {
        storedData = x;  // Stored permanently in blockchain
    }

    function get() public view returns (uint) {
        return storedData;
    }
}

Slide 8: Transactions and Gas Fees

Code Example: Transactions and Gas Fees

pragma solidity ^0.8.0;

contract GasExample {
    uint public data;

    function storeData(uint x) public {
        data = x;  // This consumes gas
    }

    function calculateGas() public view returns (uint) {
        return tx.gasprice;  // Returns the gas price of the transaction
    }
}

Slide 9: Events

Code Example: Events

pragma solidity ^0.8.0;

contract EventExample {
    event DataStored(uint data);

    function store(uint data) public {
        emit DataStored(data);  // Emits an event
    }
}

Slide 10: Important Solidity Concepts

Before diving into scenarios and use cases, let’s briefly explain some fundamental concepts, such as msg.sender, msg.value, tx.gasprice, and block.timestamp, that are frequently used in Solidity smart contracts.

  1. msg.sender:

    • Refers to the address that initiated the transaction. In the context of a function, msg.sender represents the caller of the function.
    • Used to ensure only certain addresses (like the contract owner) can perform specific actions.

    Example:

    address public owner;
    
    constructor() {
        owner = msg.sender;  // Sets the owner as the person who deployed the contract
    }
    
  2. msg.value:

    • Represents the amount of Ether (in wei) sent along with the transaction.
    • Used to transfer Ether or check if the correct amount of Ether has been sent.

    Example:

    function buyToken() public payable {
        require(msg.value == 1 ether, "Send exactly 1 Ether");
        // Process token purchase
    }
    
  3. tx.gasprice:

    • Returns the gas price for the current transaction. Useful for calculating how much gas will be consumed.

    Example:

    function getGasPrice() public view returns (uint) {
        return tx.gasprice;
    }
    
  4. block.timestamp:

    • Returns the current block’s timestamp in seconds since the Unix epoch. Often used in time-based conditions.

    Example:

    uint public deadline = block.timestamp + 1 days;
    
    function isExpired() public view returns (bool) {
        return block.timestamp > deadline;
    }
    

Slide 11: Basic Use Cases and Scenarios

Here are five common use cases for Solidity smart contracts, each with an example contract demonstrating how the scenario is implemented.


Scenario 1: Simple Wallet Contract

Code Example:

pragma solidity ^0.8.0;

contract SimpleWallet {
    address public owner;

    constructor() {
        owner = msg.sender;  // The deployer of the contract is the owner
    }

    // Allow anyone to deposit Ether into the contract
    function deposit() public payable {}

    // Only the owner can withdraw the balance
    function withdraw(uint amount) public {
        require(msg.sender == owner, "Only the owner can withdraw");
        require(address(this).balance >= amount, "Insufficient balance");
        payable(owner).transfer(amount);
    }

    // Get the balance of the contract
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

Scenario 2: Timed Auction Contract

Code Example:

pragma solidity ^0.8.0;

contract Auction {
    address public owner;
    uint public highestBid;
    address public highestBidder;
    uint public auctionEndTime;

    constructor(uint _durationMinutes) {
        owner = msg.sender;
        auctionEndTime = block.timestamp + _durationMinutes * 1 minutes;
    }

    // Place a bid during the auction
    function bid() public payable {
        require(block.timestamp < auctionEndTime, "Auction has ended");
        require(msg.value > highestBid, "There already is a higher bid");

        highestBid = msg.value;
        highestBidder = msg.sender;
    }

    // End the auction and send the highest bid to the owner
    function endAuction() public {
        require(msg.sender == owner, "Only the owner can end the auction");
        require(block.timestamp >= auctionEndTime, "Auction is still ongoing");

        payable(owner).transfer(highestBid);
    }
}

Scenario 3: Crowdfunding Contract

Code Example:

pragma solidity ^0.8.0;

contract Crowdfunding {
    address public owner;
    uint public goal;
    uint public deadline;
    mapping(address => uint) public contributions;

    constructor(uint _goal, uint _durationMinutes) {
        owner = msg.sender;
        goal = _goal;
        deadline = block.timestamp + _durationMinutes * 1 minutes;
    }

    // Contribute to the project
    function contribute() public payable {
        require(block.timestamp < deadline, "Deadline has passed");
        contributions[msg.sender] += msg.value;
    }

    // Claim funds if the goal is met
    function claimFunds() public {
        require(msg.sender == owner, "Only owner can claim funds");
        require(address(this).balance >= goal, "Goal not reached");
        require(block.timestamp >= deadline, "Crowdfunding still ongoing");

        payable(owner).transfer(address(this).balance);
    }

    // Refund contributions if the goal is not met
    function refund() public {
        require(block.timestamp >= deadline, "Crowdfunding still ongoing");
        require(address(this).balance < goal, "Goal was reached");

        uint contribution = contributions[msg.sender];
        contributions[msg.sender] = 0;
        payable(msg.sender).transfer(contribution);
    }
}

Scenario 4: Token Vesting Contract

Code Example:

pragma solidity ^0.8.0;

contract TokenVesting {
    address public beneficiary;
    uint public releaseTime;
    uint public tokenAmount;

    constructor(address _beneficiary, uint _tokenAmount, uint _releaseDurationMinutes) {
        beneficiary = _beneficiary;
        tokenAmount = _tokenAmount;
        releaseTime = block.timestamp + _releaseDurationMinutes * 1 minutes;
    }

    // Claim tokens after the release time
    function claimTokens() public {
        require(block.timestamp >= releaseTime, "Tokens are still locked");
        require(msg.sender == beneficiary, "Only beneficiary can claim tokens");
        
        // Transfer the tokens (pseudo-code)
        // _transferTokens(beneficiary, tokenAmount);
    }
}

Scenario 5: Voting Contract

Code Example:

pragma solidity ^0.8.0;

contract Voting {
    address public owner;
    mapping(string => uint) public votes;
    mapping(address => bool) public hasVoted;

    constructor() {
        owner = msg.sender;
    }

    // Vote for a proposal
    function vote(string memory proposal) public {
        require(!hasVoted[msg.sender], "You have already voted");
        
        votes[proposal]++;
        hasVoted[msg.sender] = true;
    }

    // Get the number of votes for a proposal
    function getVotes(string memory proposal) public view returns (uint) {
        return votes[proposal];
    }

    // Owner can finalize the vote
    function finalizeVote() public {
        require(msg.sender == owner, "Only the owner can finalize the vote");
        // Finalize voting process (e.g., declare winner)
    }
}

Slide 12: ERC20 Token Standard

Code Example: ERC20 Token

pragma solidity ^0.8.0;

interface IERC20 {
    function transfer(address recipient, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

contract MyToken is IERC20 {
    string public name = "MyToken";
    string public symbol = "MTK";
    uint8 public decimals = 18;
    uint256 public totalSupply = 1000000 * 10**18;
    
    mapping(address => uint256) public balances;

    constructor() {
        balances[msg.sender] = totalSupply;
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[recipient] += amount;
        return true;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return balances[account];
    }
}

Slide 13: ERC721 (NFT) Token Standard

Code Example: ERC721 Token

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MyNFT is ERC721 {
    uint public nextTokenId;
    address public admin;

    constructor() ERC721('MyNFT', 'MNFT') {
        admin = msg.sender;
    }

    function mint(address to) external {
        require(msg.sender == admin, "Only admin can mint");
        _safeMint(to, nextTokenId);
        nextTokenId++;
    }
}

Slide 14: Conclusion